﻿using System;
using System.Collections.Generic;
using System.Text;
using HAVNet.Intros.Parsing; /* TODO: cambiar esta referencia por usos locales en toda la apli */


namespace HAVNet.Intros.AST
{
    public class ASTMemberDeclOperator : ASTMemberDeclStruct
    {
        const int
            plusOp  = 0x00000001, minusOp   = 0x00000002, notOp     = 0x00000004, tildeOp   = 0x00000008,
            incOp   = 0x00000010, decOp     = 0x00000020, trueOp    = 0x00000040, falseOp   = 0x00000080,
            timesOp = 0x00000100, divOp     = 0x00000200, modOp     = 0x00000400, andOp     = 0x00000800,
            orOp    = 0x00001000, xorOp     = 0x00002000, lshiftOp  = 0x00004000, rshiftOp  = 0x00008000,
            eqOp    = 0x00010000, neqOp     = 0x00020000, gtOp      = 0x00040000, ltOp      = 0x00080000,
            gteOp   = 0x00100000, lteOp     = 0x00200000,
            unaryOp = plusOp | minusOp | notOp  | tildeOp   | incOp | decOp | trueOp| falseOp,
            binaryOp= plusOp | minusOp | timesOp| divOp     | modOp | andOp | orOp  | xorOp | lshiftOp | rshiftOp | eqOp | neqOp | gtOp | ltOp | gteOp | lteOp;

        public bool     isPartial   { get; set; }
        public ASTType  type        { get; set; }
        public int      overOp      { get; set; }
        public readonly ASTFormalParamList fpl = new ASTFormalParamList();
        public ASTBlock block       { get; set; }

        public override string ToString ()
        {
            // operatorsMod = publicMod | unsafeMod | staticMod | externMod,
            string mods = "";

            if (Mods.has(modifiers, Mods.publicMod)) mods += "public ";
            if (Mods.has(modifiers, Mods.unsafeMod)) mods += "unsafe ";
            if (Mods.has(modifiers, Mods.staticMod)) mods += "static ";
            if (Mods.has(modifiers, Mods.externMod)) mods += "extern ";

            return
                mods                            +
                (isPartial ? " partial " : "")  +
                type.ToString ()                +
                " operator "                    +
                overOpToString (overOp)         +
                " (" + fpl.ToString() + ") "    +
                (block == null ? ";" : block.ToString());
        }
        
        public static string overOpToString (int overOp)
        {
            //  OverloadableOp<out int op>				    (. op = plusOp; .)
            //  =												
            //  (
            //  /* unary operators */
            //      "+"											
            //  | "-"										(. op = minusOp;	.)
            //  | "!"										(. op = notOp;	.)
            //  | "~"										(. op = tildeOp;	.)
            //  | "++"										(. op = incOp;	.)
            //  | "--"										(. op = decOp;	.)
            //  | "true"									(. op = trueOp;	.)
            //  | "false"									(. op = falseOp;	.)
            //  | /* binary operators (plus +, -) */
            //  "*"											(. op = timesOp;	.)
            //  | "/"										(. op = divOp;	.)
            //  | "%"										(. op = modOp;	.)
            //  | "&"										(. op = andOp;	.)
            //  | "|"										(. op = orOp;	.)
            //  | "^"										(. op = xorOp;	.)
            //  | "<<"										(. op = lshiftOp;.)
            //  | "=="										(. op = eqOp;	.)
            //  | "!="										(. op = neqOp;	.)
            //  | ">"										(. op = gtOp;	.)
            //  [											(. if (la.pos > t.pos+1) Error ("no whitespace allowed in right shift operator"); .)
            //      ">"										(. op = rshiftOp;.)
            //  ]
            //  | "<"									    (. op = ltOp;	.)
            //  | ">="										(. op = gteOp;	.)
            //  | "<="										(. op = lteOp;	.) //  )

            switch (overOp)
            {
                case plusOp     : return "+";
                case minusOp    : return "-";
                case notOp      : return "!";
                case tildeOp    : return "~";
                case incOp      : return "++";
                case decOp      : return "--";
                case trueOp     : return "true";
                case falseOp    : return "false";
                case timesOp    : return "*";
                case divOp      : return "/";
                case modOp      : return "%";
                case andOp      : return "&";
                case orOp       : return "|";
                case xorOp      : return "^";
                case lshiftOp   : return "<<";
                case eqOp       : return "==";
                case neqOp      : return "!=";
                case gtOp       : return ">";
                case rshiftOp   : return ">>";
                case ltOp       : return "<";
                case gteOp      : return ">=";
                case lteOp      : return "<=";
            }

            return "";
        }
    }
}
